/*
  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.

  Copyright (c) 2006-2009 PRO ACTIVE SAS - www.proactive-group.com
   
  Ref_AskCts512b.c
  ----------------

  This is the reference applications that shows how to read/write data
  in a ASK CTS512B tag.
  
  JDA 12/04/2007 : initial release

*/
#include "products/springprox/springprox.h"

#include <stdio.h>
#include <string.h>

SWORD SPROX_ConfigureForCTS(void);

SWORD SPROX_CTS512_Request(BYTE req_data[2]);
SWORD SPROX_CTS512_Select(const BYTE sel_param[2], BYTE sel_result[2]);
SWORD SPROX_CTS512_Deactivate(void);
SWORD SPROX_CTS512_Read(BYTE addr, BYTE value[2]);
SWORD SPROX_CTS512_MultiRead(BYTE addr, BYTE value[8]);
SWORD SPROX_CTS512_Update(BYTE addr, BYTE data[2]);

int main(int argc, char **argv)
{
  SWORD rc;
  char s_buffer[64];
  BYTE code[2];
  BYTE serial[2];
  BYTE data[64];
  BYTE addr;

  char *device = NULL;

  if (argc > 1)
    device = argv[1];

  printf("SpringCard SDK for K531/SpringProx-CF/CSB Legacy\n");
  printf("\n");
  printf("ASK CTS 512B reference demo\n");
  printf("---------------------------\n");
  printf("www.springcard.com\n\n");

  rc = SPROX_GetLibrary(s_buffer, sizeof(s_buffer));
  if (rc != MI_OK)
  {
    printf("Failed to get API version\n");
    goto done;
  }
  printf("API version : %s\n", s_buffer);
  printf("\n");

  /* Open reader */
  /* ----------- */

  rc = SPROX_ReaderOpen(device);
  if (rc != MI_OK)
  {
    printf("Reader not found\n");
    goto done;
  }

  rc = SPROX_ReaderGetDevice(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader found on %s\n", s_buffer);

  rc = SPROX_ReaderGetFirmware(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader firwmare is %s\n", s_buffer);

  /* Configure reader for ASK memory cards operation */
  /* ----------------------------------------------- */
  rc = SPROX_ConfigureForCTS();
  if (rc != MI_OK)
  {
    printf("Failed to configure the reader\n");
    return 0;
  }

  /* RF field ON */
  SPROX_ControlRF(TRUE);

  printf("Put your ASK CTS 512B card on the reader...\n");

  /* Select a compliant tag */
  /* ---------------------- */
  for (;;)
  {
    rc = SPROX_CTS512_Request(code);
    if (rc == MI_OK)
    {
      if ((code[1] & 0xF0) != 0x60)
        printf("Hum, seems that this is NOT a CTS512B. Trying to select anyway...\n");
      
      rc = SPROX_CTS512_Select(NULL, serial);
      if (rc == MI_OK)
        break;
      if ((code[1] & 0xF0) != 0x60)        
        printf("Error %d on select. You've been warned !\n", rc);
      else
        printf("Error %d on select.\n", rc);
    }
  }

  printf("Tag found, product code = %02X, fab code = %02X, serial = %02X%02X\n", code[0], code[1], serial[1], serial[0]);

  printf("Reading 32 blocks...\n");
  for (addr = 0; addr < 32; addr++)
  {
    rc = SPROX_CTS512_Read(addr, &data[2*addr]);
    if (rc == MI_OK)
    {
      printf("Block %02d : %02X%02X\n", addr, data[2*addr], data[2*addr + 1]);
    } else
    {
      printf("Block %02d : Read failed, error %d\n", addr, rc);
    }
  }

  printf("Writing blocks 5 to 32...\n");
  for (addr = 5; addr < 32; addr++)
  {
    data[2 * addr]     = 0xA0 | addr;
    data[2 * addr + 1] = 0xB0 | addr;
    rc = SPROX_CTS512_Update(addr, &data[2 * addr]);
    if (rc != MI_OK)
    {
      printf("Block %02d : Update failed, error %d\n", addr, rc);
    }
  }


  printf("Reading 32 blocks again\n");
  for (addr = 0; addr < 32; addr+=4)
  {
    rc = SPROX_CTS512_MultiRead(addr, &data[2 * addr]);
    if (rc == MI_OK)
    {
      BYTE i;

      printf("Block %02d :", addr);
      for (i=0; i<8; i+=2)
        printf(" %02X%02X", data[2*addr+i], data[2*addr+i+1]);
      printf("\n");
    } else
    {
      printf("Block %02d : MultiRead failed, error %d\n", addr, rc);
    }
  }

  printf("Erasing blocks 5 to 32...\n");
  for (addr = 5; addr < 32; addr++)
  {
    data[2 * addr]     = 0x00;
    data[2 * addr + 1] = 0x00;
    rc = SPROX_CTS512_Update(addr, &data[2 * addr]);
    if (rc != MI_OK)
    {
      printf("Block %02d : Update failed, error %d\n", addr, rc);
    }
  }

  printf("Reading 32 blocks again\n");
  for (addr = 0; addr < 32; addr+=4)
  {
    rc = SPROX_CTS512_MultiRead(addr, &data[2 * addr]);
    if (rc == MI_OK)
    {
      BYTE i;

      printf("Block %02d :", addr);
      for (i=0; i<8; i+=2)
        printf(" %02X%02X", data[2*addr+i], data[2*addr+i+1]);
      printf("\n");
    } else
    {
      printf("Block %02d : MultiRead failed, error %d\n", addr, rc);
    }
  }

  rc = SPROX_CTS512_Deactivate();
  if (rc != MI_OK)
  {
    printf("Deactivation error %d\n", rc);
  }

  /* Close the reader */
  SPROX_ControlRF(FALSE);
  SPROX_ReaderClose();

done:
  /* Display last error */
  if (rc == MI_OK)
  {
    printf("Done\n");
  } else
  {
    printf("%s (%d)\n", SPROX_GetErrorMessage(rc), rc);
  }
  return 0;
}

/*
 * Configure the reader for ASK CTS operation
 * ------------------------------------------
 */
SWORD SPROX_ConfigureForCTS(void)
{
  SWORD rc;

  /* Enter ISO 14443-B mode */
  rc = SPROX_SetConfig(CFG_MODE_ISO_14443_B);
  if (rc != MI_OK)
    return rc;

  rc = WriteRIC(0x17, 0x00);
  if (rc != MI_OK)
    return rc;

  rc = WriteRIC(0x1D, 0xFE);
  if (rc != MI_OK)
    return rc;

  return MI_OK;
}

SWORD SPROX_CTS512_Request(BYTE req_data[2])
{
  BYTE buffer[4];
  WORD len = 4;
  SWORD rc;

  buffer[0] = 0x10;

  /* Timeout = 1ms */
  rc = SPROX_B_Exchange(buffer, 3, buffer, &len, TRUE, 106);
  if (rc != MI_OK)
    return rc;

  /* 2 bytes (+CRC) expected */
  if (len != 4)
    return MI_WRONG_LENGTH;

  if (req_data != NULL)
    memcpy(req_data, buffer, 2);

  return MI_OK;
}

SWORD SPROX_CTS512_Select(const BYTE sel_param[2], BYTE sel_result[2])
{
  BYTE buffer[5];
  WORD len = 4;
  SWORD rc;

  buffer[0] = 0x9F;
  if (sel_param != NULL)
    memcpy(&buffer[1], sel_param, 2);
  else
    memset(&buffer[1], 0xFF, 2);

  /* Timeout = 1ms */
  rc = SPROX_B_Exchange(buffer, 5, buffer, &len, TRUE, 106);
  if (rc != MI_OK)
    return rc;

  /* 2 bytes (+CRC) expected */
  if (len != 4)
    return MI_WRONG_LENGTH;

  if (sel_result != NULL)
    memcpy(sel_result, buffer, 2);

  return MI_OK;
}

SWORD SPROX_CTS512_Deactivate(void)
{
  BYTE buffer[3];
  WORD len = 3;
  SWORD rc;

  /* DEACTIVATE command */
  buffer[0] = 0x80;

  /* Timeout = 1ms, but no answer expected */
  rc = SPROX_B_Exchange(buffer, 3, buffer, &len, TRUE, 106);
  if (rc == MI_NOTAGERR)
    rc = MI_OK;

  return rc;
}

SWORD SPROX_CTS512_Read(BYTE addr, BYTE value[2])
{
  BYTE buffer[4];
  WORD len = 4;
  SWORD rc;

  /* READ command */
  buffer[0] = 0xC0 | (addr & 0x1F);

  /* Timeout = 1ms */
  rc = SPROX_B_Exchange(buffer, 3, buffer, &len, TRUE, 106);
  if (rc != MI_OK)
    return rc;

  /* 2 bytes (+CRC) expected */
  if (len != 4)
    return MI_WRONG_LENGTH;

  if (value != NULL)
    memcpy(value, buffer, 2);

  return MI_OK;
}

SWORD SPROX_CTS512_MultiRead(BYTE addr, BYTE value[8])
{
  BYTE buffer[10];
  WORD len = 10;
  SWORD rc;

  /* READ command */
  buffer[0] = 0x20 | (addr & 0x1F);

  /* Timeout = 1ms */
  rc = SPROX_B_Exchange(buffer, 3, buffer, &len, TRUE, 212);
  if (rc != MI_OK)
    return rc;

  /* 8 bytes (+CRC) expected */
  if (len != 10)
    return MI_WRONG_LENGTH;

  if (value != NULL)
    memcpy(value, buffer, 8);

  return MI_OK;
}

SWORD SPROX_CTS512_Update(BYTE addr, BYTE data[2])
{
  BYTE buf[16];
  WORD len = sizeof(buf);
  SWORD rc;

  /* Before writing we must read the system bits */
  rc = SPROX_CTS512_Read(1, NULL);
  if (rc != MI_OK) return rc;

  /* UPDATE command with 2 bytes of data */
  buf[0] = 0x60 | (addr & 0x1F);
  buf[1] = data[0];
  buf[2] = data[1];

  /* Timeout = 2ms, but no answer expected */
  len = sizeof(buf);
  rc = SPROX_B_Exchange(buf, 5, buf, &len, TRUE, 212);
  if (rc == MI_NOTAGERR)
    rc = MI_OK;

  return rc;
}
